#pragma once

#include "stdafx.h"
#include "dbg_log_output.h"

class MFObjectActivate : public IMFActivate
{
	ULONG RefCount = 1;
	IClassFactory* pClassFactory = NULL;
	IMFAttributes* pAttributes = NULL;
	IUnknown* pObject = NULL;
public:
	MFObjectActivate(IClassFactory* pClassFactory)
	{
		MFCreateAttributes(&pAttributes,0);
		pClassFactory->AddRef();
		this->pClassFactory = pClassFactory;
	}
	~MFObjectActivate()
	{
		SAFE_RELEASE(pAttributes);
		SAFE_RELEASE(pClassFactory);
		SAFE_RELEASE(pObject);
	}
public:
	IFACEMETHODIMP QueryInterface(REFIID iid,void** ppv)
	{
		if (ppv == NULL)
			return E_POINTER;
		if (iid == IID_IUnknown || iid == IID_IMFActivate || iid == IID_IMFAttributes)
		{
			*ppv = static_cast<IUnknown*>(this);
			AddRef();
			return S_OK;
		}
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	IFACEMETHODIMP_(ULONG) AddRef()
	{
		return (ULONG)InterlockedIncrement(&RefCount);
	}
	IFACEMETHODIMP_(ULONG) Release()
	{
		ULONG _RefCount = (ULONG)InterlockedDecrement(&RefCount);
		if (_RefCount == 0)
			delete this;
		return _RefCount;
	}
public:
	STDMETHODIMP GetItem(REFGUID guidKey,PROPVARIANT *pValue)
	 {
		 return pAttributes->GetItem(guidKey,pValue);
	 }
	 STDMETHODIMP GetItemType(REFGUID guidKey,MF_ATTRIBUTE_TYPE *pType)
	 {
		 return pAttributes->GetItemType(guidKey,pType);
	 }
	 STDMETHODIMP CompareItem(REFGUID guidKey,REFPROPVARIANT Value,BOOL *pbResult)
	 {
		 return pAttributes->CompareItem(guidKey,Value,pbResult);
	 }
	 STDMETHODIMP Compare(IMFAttributes *pTheirs,MF_ATTRIBUTES_MATCH_TYPE MatchType,BOOL *pbResult)
	 {
		 return pAttributes->Compare(pTheirs,MatchType,pbResult);
	 }
	 STDMETHODIMP GetUINT32(REFGUID guidKey,UINT32 *punValue)
	 {
		 return pAttributes->GetUINT32(guidKey,punValue);
	 }
	 STDMETHODIMP GetUINT64(REFGUID guidKey,UINT64 *punValue)
	 {
		 return pAttributes->GetUINT64(guidKey,punValue);
	 }
	 STDMETHODIMP GetDouble(REFGUID guidKey,double *pfValue)
	 {
		 return pAttributes->GetDouble(guidKey,pfValue);
	 }
	 STDMETHODIMP GetGUID(REFGUID guidKey,GUID *pguidValue)
	 {
		 return pAttributes->GetGUID(guidKey,pguidValue);
	 }
	 STDMETHODIMP GetStringLength(REFGUID guidKey,UINT32 *pcchLength)
	 {
		 return pAttributes->GetStringLength(guidKey,pcchLength);
	 }
	 STDMETHODIMP GetString(REFGUID guidKey,LPWSTR pwszValue,UINT32 cchBufSize,UINT32 *pcchLength)
	 {
		 return pAttributes->GetString(guidKey,pwszValue,cchBufSize,pcchLength);
	 }
	 STDMETHODIMP GetAllocatedString(REFGUID guidKey,LPWSTR *ppwszValue,UINT32 *pcchLength)
	 {
		 return pAttributes->GetAllocatedString(guidKey,ppwszValue,pcchLength);
	 }
	 STDMETHODIMP GetBlobSize(REFGUID guidKey,UINT32 *pcbBlobSize)
	 {
		 return pAttributes->GetBlobSize(guidKey,pcbBlobSize);
	 }
	 STDMETHODIMP GetBlob(REFGUID guidKey,UINT8 *pBuf,UINT32 cbBufSize,UINT32 *pcbBlobSize)
	 {
		 return pAttributes->GetBlob(guidKey,pBuf,cbBufSize,pcbBlobSize);
	 }
	 STDMETHODIMP GetAllocatedBlob(REFGUID guidKey,UINT8 **ppBuf,UINT32 *pcbSize)
	 {
		 return pAttributes->GetAllocatedBlob(guidKey,ppBuf,pcbSize);
	 }
	 STDMETHODIMP GetUnknown(REFGUID guidKey,REFIID riid,LPVOID *ppv)
	 {
		 return pAttributes->GetUnknown(guidKey,riid,ppv);
	 }
	 STDMETHODIMP SetItem(REFGUID guidKey,REFPROPVARIANT Value)
	 {
		 return pAttributes->SetItem(guidKey,Value);
	 }
	 STDMETHODIMP DeleteItem(REFGUID guidKey)
	 {
		 return pAttributes->DeleteItem(guidKey);
	 }
	 STDMETHODIMP DeleteAllItems()
	 {
		 return pAttributes->DeleteAllItems();
	 }
	 STDMETHODIMP SetUINT32(REFGUID guidKey,UINT32 unValue)
	 {
		 return pAttributes->SetUINT32(guidKey,unValue);
	 }
	 STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue)
	 {
		 return pAttributes->SetUINT64(guidKey,unValue); 
	 }
	 STDMETHODIMP SetDouble(REFGUID guidKey,double fValue)
	 {
		 return pAttributes->SetDouble(guidKey,fValue);
	 }
	 STDMETHODIMP SetGUID(REFGUID guidKey,REFGUID guidValue)
	 {
		 return pAttributes->SetGUID(guidKey,guidValue);
	 }
	 STDMETHODIMP SetString(REFGUID guidKey,LPCWSTR wszValue)
	 {
		 return pAttributes->SetString(guidKey,wszValue);
	 }
	 STDMETHODIMP SetBlob(REFGUID guidKey,const UINT8 *pBuf,UINT32 cbBufSize)
	 {
		 return pAttributes->SetBlob(guidKey,pBuf,cbBufSize);
	 }
	 STDMETHODIMP SetUnknown(REFGUID guidKey,IUnknown *pUnknown)
	 {
		 return pAttributes->SetUnknown(guidKey,pUnknown);
	 }
	 STDMETHODIMP LockStore()
	 {
		 return pAttributes->LockStore();
	 }
	 STDMETHODIMP UnlockStore()
	 {
		 return pAttributes->UnlockStore();
	 }
	 STDMETHODIMP GetCount(UINT32 *pcItems)
	 {
		 return pAttributes->GetCount(pcItems);
	 }
	 STDMETHODIMP GetItemByIndex(UINT32 unIndex,GUID *pguidKey,PROPVARIANT *pValue)
	 {
		 return pAttributes->GetItemByIndex(unIndex,pguidKey,pValue);
	 }
	 STDMETHODIMP CopyAllItems(IMFAttributes *pDest)
	 {
		 return pAttributes->CopyAllItems(pDest);
	 }
public:
	STDMETHODIMP ActivateObject(REFIID riid,void** ppv)
	{
		LogDbgPrint("MF::ActivateObject...");
		if (ppv == NULL)
			return E_POINTER;
		if (pObject)
		{
			pObject->AddRef();
			*ppv = pObject;
			return S_OK;
		}else{
			HRESULT hr = pClassFactory->CreateInstance(NULL,riid,ppv);
			LogDbgPrint("ActivateObject HR:0x%08X",hr);
			if (FAILED(hr))
				return hr;
			pObject = (IUnknown*)(*ppv);
			pObject->AddRef();
			return S_OK;
		}
	}
	STDMETHODIMP ShutdownObject()
	{
		LogDbgPrint("MF::ShutdownObject...");
		if (pObject == NULL)
			return E_UNEXPECTED;
		SAFE_RELEASE(pObject);
		return S_OK;
	}
	STDMETHODIMP DetachObject()
	{
		if (pObject == NULL)
			return E_UNEXPECTED;
		SAFE_RELEASE(pObject);
		return S_OK;
	}
};